//TODO: 
//  str in Rust is utf-8 char; 
//  char.len_utf8 => bytes_len()
//  str.len() ??????
struct GtpParser<'g> {
    input: &'g str
}

impl <'g> GtpParser<'g> {

    pub fn from_str(input: &'g str) -> Self {
        GtpParser{ input }
    }


    // return pointer next to ...key= if find key => Result<&'g str, i32>
    // return None 
    //      => format error  Result::Err(SyntaxError(index))
    //      => not found  Result::Ok(Option<&'g str>);
    pub fn find(&mut self, key: &str) -> Option<&'g str> {
        if self.input.len() > 0 && key.len() > 0 { 
            return self.pairs(key);
        }
        None
    }
    fn pairs(&mut self, key: &str) -> Option<&'g str>{
        let k = self.key()?; // parse key

        if self.next_separator() == false { //parse "="
            return None
        }
        if k == key {  // find key Ok => break; and return the Range[..]
            return Some(self.input);
        }
        
        //if key not equal => parse the value: TODO: ???
        if self.value().is_none() {  // parse value failed
            return None;
        }
        //TODO: temp return 
        Some(self.input)
        //TODO: loop
    }

    pub fn peek_char(& self) -> Option<char> {
        self.input.chars().next()
    }
    pub fn next_char(&mut self) -> Option<char> {
        let ch = self.peek_char()?;
        self.input = &self.input[ch.len_utf8()..];
        Some(ch)
    }

    //TODO: 
    // loop -> 
    //  1. { -> object ; 
    //  2. [ -> array
    //  3. not [,|]|}] => string
    fn value(&mut self) -> Option<&'g str> {
        match self.peek_char() {
            Some(ch) => {
                match ch {
                    '{' => {
                        self.input = &self.input[ch.len_utf8()..];
                        return self.object();
                    }
                    '[' => {
                        self.input = &self.input[ch.len_utf8()..];
                        return self.array();
                    }
                    _   => {
                        return self.string(); //regular string
                    }
                }//match(ch)
            }//Some(ch)
            None => {
                return self.string(); //TODO: NullString
            }
        }
    }
    fn string(&mut self) -> Option<&'g str> {
        let start  = self.input;
        let mut count = 0;
        loop {
            match self.next_char() {
                Some(ch) => {
                    match ch {
                        ',' | ']' | '}' => {
                            break; // exit the loop
                        }
                        _ => {
                            count += 1;
                        }
                    }
                }//Some(ch)
                None => {
                    break; //exit the loop
                }
            }
        }
        if count > 0 {
            self.input = &self.input[count..];
            return Some(&start[0..count]);
        }
        None
    }

    fn object(&mut self) -> Option<&'g str> {
        //TODO:
        None
    }
    fn array(&mut self) -> Option<&'g str> {
        //TODO:
        None
    }

    fn key(&mut self) -> Option<&'g str> {
        const KEY_LEN: usize = 3;
        if self.input.len() > KEY_LEN {
            let ret = Some(&self.input[0..KEY_LEN]);
            self.input = &self.input[KEY_LEN..];
            return ret;
        }
        None
    }
    fn next_separator(&mut self) -> bool {
        match self.next_char(){
            Some(ch) => {
                return ch == '=';
            }
            None => {
                return false;
            }
        }
    }
}


//TODO: study the Option<> && Result<> first ?????

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_option() {
        let o = Some(2);
        { // extract v of Some(v) use if let
            if let Some(d) = o {
                if d != 2 {
                    assert!(false);
                }
            } 
        }
        { // extract v for operation of Some(v) use match
            match o {
                Some(num) => assert!(2 == num),
                None =>  assert!(false),
            }
        }

        //let number = if condition {5} else {6};
        {
            let num = match o {
                Some(num) => num,
                None =>  return ,
            };
            assert_eq!(2, num);
        }
        {
            let num = match o {
                Some(num) => { num },
                None =>  { 0 },
            };
            assert_eq!(2, num);
        }
    }

    #[test]
    fn test_str(){
        let str = "hello";
        let abc = &str[str.len()..];
        assert_eq!(0, abc.len());
        assert_eq!("", abc);
    }

    #[test]
    fn test_result(){
        let e = Result::<(),i32>::Err(-1);
        match e {
            Ok(_) => {
                assert!(false);
            },
            Err(errno) => {
                assert_eq!(-1, errno);
            },
        }
    }

    #[test]
    fn test_parser_peek_char(){
        {//Test peek_char
            let gtp = "{";
            let parser = GtpParser::from_str(gtp);
            assert_eq!(Some('{'), parser.peek_char());
        }
        {
            let gtp = "";
            let parser = GtpParser::from_str(gtp);
            assert_eq!(None, parser.peek_char());

        }
    }
    #[test]
    fn test_parser(){
        {// first key is found
            let gtp = "X02=hello";
            let mut parser = GtpParser::from_str(gtp);
            assert_eq!(Some(&gtp["X02=".len()..]), parser.find("X02"));
        }
        { // first key is not found
            //let gtp = "X01=hello,X02=world";
            //let mut parser = GtpParser::from_str(gtp);
            //assert_eq!(Some(&gtp["X01=hello".len()..]), parser.find("X02"));
        }

    }
}
